- 
                Notifications
    You must be signed in to change notification settings 
- Fork 15k
[PAC][lld][AArch64][ELF] Support signed GOT #113815
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| 
 This stack of pull requests is managed by Graphite. Learn more about stacking. | 
| @llvm/pr-subscribers-lld Author: Daniil Kovalev (kovdan01) ChangesDepends on #113811 Support  Full diff: https://github.com/llvm/llvm-project/pull/113815.diff 8 Files Affected: 
 diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 28e0fce6a6f499..86f509f3fd78a7 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -202,11 +202,16 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
   case R_AARCH64_LD64_GOT_LO12_NC:
   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
     return R_GOT;
+  case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
+  case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
+    return R_AARCH64_AUTH_GOT;
   case R_AARCH64_LD64_GOTPAGE_LO15:
     return R_AARCH64_GOT_PAGE;
   case R_AARCH64_ADR_GOT_PAGE:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
     return R_AARCH64_GOT_PAGE_PC;
+  case R_AARCH64_AUTH_ADR_GOT_PAGE:
+    return R_AARCH64_AUTH_GOT_PAGE_PC;
   case R_AARCH64_GOTPCREL32:
   case R_AARCH64_GOT_LD_PREL19:
     return R_GOT_PC;
@@ -258,6 +263,7 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
     return read64(ctx, buf + 8);
   case R_AARCH64_NONE:
   case R_AARCH64_GLOB_DAT:
+  case R_AARCH64_AUTH_GLOB_DAT:
   case R_AARCH64_JUMP_SLOT:
     return 0;
   case R_AARCH64_ABS16:
@@ -529,9 +535,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
       write32(ctx, loc, val);
     break;
   case R_AARCH64_ADD_ABS_LO12_NC:
+  case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
     write32Imm12(loc, val);
     break;
   case R_AARCH64_ADR_GOT_PAGE:
+  case R_AARCH64_AUTH_ADR_GOT_PAGE:
   case R_AARCH64_ADR_PREL_PG_HI21:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
   case R_AARCH64_TLSDESC_ADR_PAGE21:
@@ -581,6 +589,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
     break;
   case R_AARCH64_LDST64_ABS_LO12_NC:
   case R_AARCH64_LD64_GOT_LO12_NC:
+  case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
   case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
   case R_AARCH64_TLSDESC_LD64_LO12:
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 3b48fbe07bb082..ccc7cf8c6e2de9 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -754,6 +754,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
   case R_ARM_SBREL:
     return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
   case R_GOT:
+  case R_AARCH64_AUTH_GOT:
   case R_RELAX_TLS_GD_TO_IE_ABS:
     return r.sym->getGotVA(ctx) + a;
   case R_LOONGARCH_GOT:
@@ -781,6 +782,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
   case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
     return r.sym->getGotOffset(ctx) + a;
   case R_AARCH64_GOT_PAGE_PC:
+  case R_AARCH64_AUTH_GOT_PAGE_PC:
   case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
     return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
   case R_AARCH64_GOT_PAGE:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index d40348a7b30d8f..2d3815e58b5f67 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -210,8 +210,9 @@ static bool needsPlt(RelExpr expr) {
 }
 
 bool lld::elf::needsGot(RelExpr expr) {
-  return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
-               R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
+  return oneof<R_GOT, R_AARCH64_AUTH_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+               R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
+               R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
                R_AARCH64_GOT_PAGE, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(
       expr);
 }
@@ -933,14 +934,26 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
 
   // If preemptible, emit a GLOB_DAT relocation.
   if (sym.isPreemptible) {
-    ctx.mainPart->relaDyn->addReloc({ctx.target->gotRel, ctx.in.got.get(), off,
+    RelType gotRel = ctx.target->gotRel;
+    if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+      assert(ctx.arg.emachine == EM_AARCH64);
+      gotRel = R_AARCH64_AUTH_GLOB_DAT;
+    }
+    ctx.mainPart->relaDyn->addReloc({gotRel, ctx.in.got.get(), off,
                                      DynamicReloc::AgainstSymbol, sym, 0,
                                      R_ABS});
     return;
   }
 
   // Otherwise, the value is either a link-time constant or the load base
-  // plus a constant.
+  // plus a constant. Signed GOT requires dynamic relocation.
+  if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+    ctx.in.got->getPartition(ctx).relaDyn->addReloc(
+        {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
+         DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
+    return;
+  }
+
   if (!ctx.arg.isPic || isAbsolute(sym))
     ctx.in.got->addConstant({R_ABS, ctx.target->symbolicRel, off, 0, &sym});
   else
@@ -994,10 +1007,11 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
   // These expressions always compute a constant
   if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, R_MIPS_GOT_LOCAL_PAGE,
             R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
-            R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
-            R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, R_GOTPLT_PC,
-            R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
-            R_AARCH64_GOT_PAGE, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
+            R_AARCH64_GOT_PAGE_PC, R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC,
+            R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
+            R_GOTPLT_GOTREL, R_GOTPLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
+            R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE,
+            R_AARCH64_AUTH_GOT, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
             R_LOONGARCH_GOT_PAGE_PC>(e))
     return true;
 
@@ -1111,7 +1125,19 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
     } else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
       // Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which
       // case the NEEDS_GOT flag shouldn't get set.
-      sym.setFlags(NEEDS_GOT);
+      bool needsGotAuth =
+          (expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC);
+      uint16_t flags = sym.flags.load(std::memory_order_relaxed);
+      if (!(flags & NEEDS_GOT)) {
+        if (needsGotAuth)
+          sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
+        else
+          sym.setFlags(NEEDS_GOT);
+      } else if (needsGotAuth != static_cast<bool>(flags & NEEDS_GOT_AUTH)) {
+        fatal("both AUTH and non-AUTH GOT entries for '" + sym.getName() +
+              "' requested, but only one type of GOT entry per symbol is "
+              "supported");
+      }
     }
   } else if (needsPlt(expr)) {
     sym.setFlags(NEEDS_PLT);
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 64e67c2c968207..20d88de402ac18 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -86,7 +86,9 @@ enum RelExpr {
   // of a relocation type, there are some relocations whose semantics are
   // unique to a target. Such relocation are marked with R_<TARGET_NAME>.
   R_AARCH64_GOT_PAGE_PC,
+  R_AARCH64_AUTH_GOT_PAGE_PC,
   R_AARCH64_GOT_PAGE,
+  R_AARCH64_AUTH_GOT,
   R_AARCH64_PAGE_PC,
   R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
   R_AARCH64_TLSDESC_PAGE,
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 339f32e05f1625..470bae23832d7d 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -54,6 +54,7 @@ enum {
   NEEDS_TLSGD_TO_IE = 1 << 6,
   NEEDS_GOT_DTPREL = 1 << 7,
   NEEDS_TLSIE = 1 << 8,
+  NEEDS_GOT_AUTH = 1 << 9,
 };
 
 // The base class for real symbol classes.
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 7a344635a1cb53..0cf45e51bc58a8 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -664,6 +664,8 @@ void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
 void GotSection::addEntry(const Symbol &sym) {
   assert(sym.auxIdx == ctx.symAux.size() - 1);
   ctx.symAux.back().gotIdx = numEntries++;
+  if (sym.hasFlag(NEEDS_GOT_AUTH))
+    authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, sym.isFunc()});
 }
 
 bool GotSection::addTlsDescEntry(const Symbol &sym) {
@@ -728,6 +730,21 @@ void GotSection::writeTo(uint8_t *buf) {
     return;
   ctx.target->writeGotHeader(buf);
   ctx.target->relocateAlloc(*this, buf);
+  for (const AuthEntryInfo &authEntry : authEntries) {
+    // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema
+    //   Signed GOT entries use the IA key for symbols of type STT_FUNC and the
+    //   DA key for all other symbol types, with the address of the GOT entry as
+    //   the modifier. The static linker must encode the signing schema into the
+    //   GOT slot.
+    //
+    // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#encoding-the-signing-schema
+    //   If address diversity is set and the discriminator
+    //   is 0 then modifier = Place
+    uint8_t *dest = buf + authEntry.offset;
+    uint64_t key = authEntry.isSymbolFunc ? /*IA*/ 0b00 : /*DA*/ 0b10;
+    uint64_t addrDiversity = 1;
+    write64(ctx, dest, (addrDiversity << 63) | (key << 60));
+  }
 }
 
 static uint64_t getMipsPageAddr(uint64_t addr) {
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 3573767671feb1..79af4e3971df51 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -131,6 +131,11 @@ class GotSection final : public SyntheticSection {
   size_t numEntries = 0;
   uint32_t tlsIndexOff = -1;
   uint64_t size = 0;
+  struct AuthEntryInfo {
+    size_t offset;
+    bool isSymbolFunc;
+  };
+  SmallVector<AuthEntryInfo, 0> authEntries;
 };
 
 // .note.GNU-stack section.
diff --git a/lld/test/ELF/aarch64-got-relocations-pauth.s b/lld/test/ELF/aarch64-got-relocations-pauth.s
new file mode 100644
index 00000000000000..f04e3d953388ce
--- /dev/null
+++ b/lld/test/ELF/aarch64-got-relocations-pauth.s
@@ -0,0 +1,94 @@
+# REQUIRES: aarch64
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %p/Inputs/shared.s -o a.o
+# RUN: ld.lld -shared a.o -o a.so
+
+#--- ok.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux ok.s -o ok.o
+
+# RUN: ld.lld ok.o a.so -pie -o external
+# RUN: llvm-readelf -r -S -x .got external | FileCheck %s --check-prefix=EXTERNAL
+
+# RUN: ld.lld ok.o a.o -pie -o local
+# RUN: llvm-readelf -r -S -x .got -s local | FileCheck %s --check-prefix=LOCAL
+
+# EXTERNAL:      Offset            Info             Type                    Symbol's Value   Symbol's Name + Addend
+# EXTERNAL-NEXT: 0000000000020380  000000010000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0
+# EXTERNAL-NEXT: 0000000000020388  000000020000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 zed + 0
+
+## Symbol's values for bar and zed are equal since they contain no content (see Inputs/shared.s)
+# LOCAL:         Offset            Info             Type                    Symbol's Value   Symbol's Name + Addend
+# LOCAL-NEXT:    0000000000020320  0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+# LOCAL-NEXT:    0000000000020328  0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+
+# EXTERNAL:      Hex dump of section '.got':
+# EXTERNAL-NEXT: 0x00020380 00000000 00000080 00000000 000000a0
+#                                          ^^
+#                                          0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+#                                                            ^^
+#                                                            0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# LOCAL: Symbol table '.symtab' contains {{.*}} entries:
+# LOCAL:    Num:    Value          Size Type    Bind   Vis       Ndx Name
+# LOCAL:         0000000000010260     0 FUNC    GLOBAL DEFAULT     6 bar
+# LOCAL:         0000000000010260     0 NOTYPE  GLOBAL DEFAULT     6 zed
+
+# LOCAL:         Hex dump of section '.got':
+# LOCAL-NEXT:    0x00020320 00000000 00000080 00000000 000000a0
+#                                          ^^
+#                                          0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+#                                                            ^^
+#                                                            0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# RUN: llvm-objdump -d external | FileCheck %s --check-prefix=EXTERNAL-ASM
+
+# EXTERNAL-ASM:      <_start>:
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr  x0, [x0, #0x380]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add  x1, x1, #0x380
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr  x0, [x0, #0x388]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add  x1, x1, #0x388
+
+# RUN: llvm-objdump -d local | FileCheck %s --check-prefix=LOCAL-ASM
+
+# LOCAL-ASM:         <_start>:
+# LOCAL-ASM-NEXT:    adrp x0, 0x20000
+# LOCAL-ASM-NEXT:    ldr  x0, [x0, #0x320]
+# LOCAL-ASM-NEXT:    adrp x1, 0x20000
+# LOCAL-ASM-NEXT:    add  x1, x1, #0x320
+# LOCAL-ASM-NEXT:    adrp x0, 0x20000
+# LOCAL-ASM-NEXT:    ldr  x0, [x0, #0x328]
+# LOCAL-ASM-NEXT:    adrp x1, 0x20000
+# LOCAL-ASM-NEXT:    add  x1, x1, #0x328
+
+.globl _start
+_start:
+  adrp x0, :got_auth:bar
+  ldr  x0, [x0, :got_auth_lo12:bar]
+  adrp x1, :got_auth:bar
+  add  x1, x1, :got_auth_lo12:bar
+  adrp x0, :got_auth:zed
+  ldr  x0, [x0, :got_auth_lo12:zed]
+  adrp x1, :got_auth:zed
+  add  x1, x1, :got_auth_lo12:zed
+
+#--- err.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux err.s -o err.o
+
+# RUN: not ld.lld err.o a.so -pie -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
+
+# ERR: error: both AUTH and non-AUTH GOT entries for 'bar' requested, but only one type of GOT entry per symbol is supported
+
+.globl _start
+_start:
+  adrp x0, :got_auth:bar
+  ldr  x0, [x0, :got_auth_lo12:bar]
+  adrp x0, :got:bar
+  ldr  x0, [x0, :got_lo12:bar]
 | 
| @llvm/pr-subscribers-lld-elf Author: Daniil Kovalev (kovdan01) ChangesDepends on #113811 Support  Full diff: https://github.com/llvm/llvm-project/pull/113815.diff 8 Files Affected: 
 diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 28e0fce6a6f499..86f509f3fd78a7 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -202,11 +202,16 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
   case R_AARCH64_LD64_GOT_LO12_NC:
   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
     return R_GOT;
+  case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
+  case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
+    return R_AARCH64_AUTH_GOT;
   case R_AARCH64_LD64_GOTPAGE_LO15:
     return R_AARCH64_GOT_PAGE;
   case R_AARCH64_ADR_GOT_PAGE:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
     return R_AARCH64_GOT_PAGE_PC;
+  case R_AARCH64_AUTH_ADR_GOT_PAGE:
+    return R_AARCH64_AUTH_GOT_PAGE_PC;
   case R_AARCH64_GOTPCREL32:
   case R_AARCH64_GOT_LD_PREL19:
     return R_GOT_PC;
@@ -258,6 +263,7 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
     return read64(ctx, buf + 8);
   case R_AARCH64_NONE:
   case R_AARCH64_GLOB_DAT:
+  case R_AARCH64_AUTH_GLOB_DAT:
   case R_AARCH64_JUMP_SLOT:
     return 0;
   case R_AARCH64_ABS16:
@@ -529,9 +535,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
       write32(ctx, loc, val);
     break;
   case R_AARCH64_ADD_ABS_LO12_NC:
+  case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
     write32Imm12(loc, val);
     break;
   case R_AARCH64_ADR_GOT_PAGE:
+  case R_AARCH64_AUTH_ADR_GOT_PAGE:
   case R_AARCH64_ADR_PREL_PG_HI21:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
   case R_AARCH64_TLSDESC_ADR_PAGE21:
@@ -581,6 +589,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
     break;
   case R_AARCH64_LDST64_ABS_LO12_NC:
   case R_AARCH64_LD64_GOT_LO12_NC:
+  case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
   case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
   case R_AARCH64_TLSDESC_LD64_LO12:
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 3b48fbe07bb082..ccc7cf8c6e2de9 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -754,6 +754,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
   case R_ARM_SBREL:
     return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
   case R_GOT:
+  case R_AARCH64_AUTH_GOT:
   case R_RELAX_TLS_GD_TO_IE_ABS:
     return r.sym->getGotVA(ctx) + a;
   case R_LOONGARCH_GOT:
@@ -781,6 +782,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
   case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
     return r.sym->getGotOffset(ctx) + a;
   case R_AARCH64_GOT_PAGE_PC:
+  case R_AARCH64_AUTH_GOT_PAGE_PC:
   case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
     return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
   case R_AARCH64_GOT_PAGE:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index d40348a7b30d8f..2d3815e58b5f67 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -210,8 +210,9 @@ static bool needsPlt(RelExpr expr) {
 }
 
 bool lld::elf::needsGot(RelExpr expr) {
-  return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
-               R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
+  return oneof<R_GOT, R_AARCH64_AUTH_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+               R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
+               R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
                R_AARCH64_GOT_PAGE, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(
       expr);
 }
@@ -933,14 +934,26 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
 
   // If preemptible, emit a GLOB_DAT relocation.
   if (sym.isPreemptible) {
-    ctx.mainPart->relaDyn->addReloc({ctx.target->gotRel, ctx.in.got.get(), off,
+    RelType gotRel = ctx.target->gotRel;
+    if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+      assert(ctx.arg.emachine == EM_AARCH64);
+      gotRel = R_AARCH64_AUTH_GLOB_DAT;
+    }
+    ctx.mainPart->relaDyn->addReloc({gotRel, ctx.in.got.get(), off,
                                      DynamicReloc::AgainstSymbol, sym, 0,
                                      R_ABS});
     return;
   }
 
   // Otherwise, the value is either a link-time constant or the load base
-  // plus a constant.
+  // plus a constant. Signed GOT requires dynamic relocation.
+  if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+    ctx.in.got->getPartition(ctx).relaDyn->addReloc(
+        {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
+         DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
+    return;
+  }
+
   if (!ctx.arg.isPic || isAbsolute(sym))
     ctx.in.got->addConstant({R_ABS, ctx.target->symbolicRel, off, 0, &sym});
   else
@@ -994,10 +1007,11 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
   // These expressions always compute a constant
   if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, R_MIPS_GOT_LOCAL_PAGE,
             R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
-            R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
-            R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, R_GOTPLT_PC,
-            R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
-            R_AARCH64_GOT_PAGE, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
+            R_AARCH64_GOT_PAGE_PC, R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC,
+            R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
+            R_GOTPLT_GOTREL, R_GOTPLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
+            R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE,
+            R_AARCH64_AUTH_GOT, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
             R_LOONGARCH_GOT_PAGE_PC>(e))
     return true;
 
@@ -1111,7 +1125,19 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
     } else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
       // Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which
       // case the NEEDS_GOT flag shouldn't get set.
-      sym.setFlags(NEEDS_GOT);
+      bool needsGotAuth =
+          (expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC);
+      uint16_t flags = sym.flags.load(std::memory_order_relaxed);
+      if (!(flags & NEEDS_GOT)) {
+        if (needsGotAuth)
+          sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
+        else
+          sym.setFlags(NEEDS_GOT);
+      } else if (needsGotAuth != static_cast<bool>(flags & NEEDS_GOT_AUTH)) {
+        fatal("both AUTH and non-AUTH GOT entries for '" + sym.getName() +
+              "' requested, but only one type of GOT entry per symbol is "
+              "supported");
+      }
     }
   } else if (needsPlt(expr)) {
     sym.setFlags(NEEDS_PLT);
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 64e67c2c968207..20d88de402ac18 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -86,7 +86,9 @@ enum RelExpr {
   // of a relocation type, there are some relocations whose semantics are
   // unique to a target. Such relocation are marked with R_<TARGET_NAME>.
   R_AARCH64_GOT_PAGE_PC,
+  R_AARCH64_AUTH_GOT_PAGE_PC,
   R_AARCH64_GOT_PAGE,
+  R_AARCH64_AUTH_GOT,
   R_AARCH64_PAGE_PC,
   R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
   R_AARCH64_TLSDESC_PAGE,
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 339f32e05f1625..470bae23832d7d 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -54,6 +54,7 @@ enum {
   NEEDS_TLSGD_TO_IE = 1 << 6,
   NEEDS_GOT_DTPREL = 1 << 7,
   NEEDS_TLSIE = 1 << 8,
+  NEEDS_GOT_AUTH = 1 << 9,
 };
 
 // The base class for real symbol classes.
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 7a344635a1cb53..0cf45e51bc58a8 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -664,6 +664,8 @@ void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
 void GotSection::addEntry(const Symbol &sym) {
   assert(sym.auxIdx == ctx.symAux.size() - 1);
   ctx.symAux.back().gotIdx = numEntries++;
+  if (sym.hasFlag(NEEDS_GOT_AUTH))
+    authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, sym.isFunc()});
 }
 
 bool GotSection::addTlsDescEntry(const Symbol &sym) {
@@ -728,6 +730,21 @@ void GotSection::writeTo(uint8_t *buf) {
     return;
   ctx.target->writeGotHeader(buf);
   ctx.target->relocateAlloc(*this, buf);
+  for (const AuthEntryInfo &authEntry : authEntries) {
+    // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema
+    //   Signed GOT entries use the IA key for symbols of type STT_FUNC and the
+    //   DA key for all other symbol types, with the address of the GOT entry as
+    //   the modifier. The static linker must encode the signing schema into the
+    //   GOT slot.
+    //
+    // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#encoding-the-signing-schema
+    //   If address diversity is set and the discriminator
+    //   is 0 then modifier = Place
+    uint8_t *dest = buf + authEntry.offset;
+    uint64_t key = authEntry.isSymbolFunc ? /*IA*/ 0b00 : /*DA*/ 0b10;
+    uint64_t addrDiversity = 1;
+    write64(ctx, dest, (addrDiversity << 63) | (key << 60));
+  }
 }
 
 static uint64_t getMipsPageAddr(uint64_t addr) {
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 3573767671feb1..79af4e3971df51 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -131,6 +131,11 @@ class GotSection final : public SyntheticSection {
   size_t numEntries = 0;
   uint32_t tlsIndexOff = -1;
   uint64_t size = 0;
+  struct AuthEntryInfo {
+    size_t offset;
+    bool isSymbolFunc;
+  };
+  SmallVector<AuthEntryInfo, 0> authEntries;
 };
 
 // .note.GNU-stack section.
diff --git a/lld/test/ELF/aarch64-got-relocations-pauth.s b/lld/test/ELF/aarch64-got-relocations-pauth.s
new file mode 100644
index 00000000000000..f04e3d953388ce
--- /dev/null
+++ b/lld/test/ELF/aarch64-got-relocations-pauth.s
@@ -0,0 +1,94 @@
+# REQUIRES: aarch64
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %p/Inputs/shared.s -o a.o
+# RUN: ld.lld -shared a.o -o a.so
+
+#--- ok.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux ok.s -o ok.o
+
+# RUN: ld.lld ok.o a.so -pie -o external
+# RUN: llvm-readelf -r -S -x .got external | FileCheck %s --check-prefix=EXTERNAL
+
+# RUN: ld.lld ok.o a.o -pie -o local
+# RUN: llvm-readelf -r -S -x .got -s local | FileCheck %s --check-prefix=LOCAL
+
+# EXTERNAL:      Offset            Info             Type                    Symbol's Value   Symbol's Name + Addend
+# EXTERNAL-NEXT: 0000000000020380  000000010000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0
+# EXTERNAL-NEXT: 0000000000020388  000000020000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 zed + 0
+
+## Symbol's values for bar and zed are equal since they contain no content (see Inputs/shared.s)
+# LOCAL:         Offset            Info             Type                    Symbol's Value   Symbol's Name + Addend
+# LOCAL-NEXT:    0000000000020320  0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+# LOCAL-NEXT:    0000000000020328  0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+
+# EXTERNAL:      Hex dump of section '.got':
+# EXTERNAL-NEXT: 0x00020380 00000000 00000080 00000000 000000a0
+#                                          ^^
+#                                          0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+#                                                            ^^
+#                                                            0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# LOCAL: Symbol table '.symtab' contains {{.*}} entries:
+# LOCAL:    Num:    Value          Size Type    Bind   Vis       Ndx Name
+# LOCAL:         0000000000010260     0 FUNC    GLOBAL DEFAULT     6 bar
+# LOCAL:         0000000000010260     0 NOTYPE  GLOBAL DEFAULT     6 zed
+
+# LOCAL:         Hex dump of section '.got':
+# LOCAL-NEXT:    0x00020320 00000000 00000080 00000000 000000a0
+#                                          ^^
+#                                          0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+#                                                            ^^
+#                                                            0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# RUN: llvm-objdump -d external | FileCheck %s --check-prefix=EXTERNAL-ASM
+
+# EXTERNAL-ASM:      <_start>:
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr  x0, [x0, #0x380]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add  x1, x1, #0x380
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr  x0, [x0, #0x388]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add  x1, x1, #0x388
+
+# RUN: llvm-objdump -d local | FileCheck %s --check-prefix=LOCAL-ASM
+
+# LOCAL-ASM:         <_start>:
+# LOCAL-ASM-NEXT:    adrp x0, 0x20000
+# LOCAL-ASM-NEXT:    ldr  x0, [x0, #0x320]
+# LOCAL-ASM-NEXT:    adrp x1, 0x20000
+# LOCAL-ASM-NEXT:    add  x1, x1, #0x320
+# LOCAL-ASM-NEXT:    adrp x0, 0x20000
+# LOCAL-ASM-NEXT:    ldr  x0, [x0, #0x328]
+# LOCAL-ASM-NEXT:    adrp x1, 0x20000
+# LOCAL-ASM-NEXT:    add  x1, x1, #0x328
+
+.globl _start
+_start:
+  adrp x0, :got_auth:bar
+  ldr  x0, [x0, :got_auth_lo12:bar]
+  adrp x1, :got_auth:bar
+  add  x1, x1, :got_auth_lo12:bar
+  adrp x0, :got_auth:zed
+  ldr  x0, [x0, :got_auth_lo12:zed]
+  adrp x1, :got_auth:zed
+  add  x1, x1, :got_auth_lo12:zed
+
+#--- err.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux err.s -o err.o
+
+# RUN: not ld.lld err.o a.so -pie -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
+
+# ERR: error: both AUTH and non-AUTH GOT entries for 'bar' requested, but only one type of GOT entry per symbol is supported
+
+.globl _start
+_start:
+  adrp x0, :got_auth:bar
+  ldr  x0, [x0, :got_auth_lo12:bar]
+  adrp x0, :got:bar
+  ldr  x0, [x0, :got_lo12:bar]
 | 
0d23449    to
    38d5936      
    Compare
  
    38d5936    to
    42ca2d9      
    Compare
  
    | Would be glad to see everyone's feedback on the changes. | 
bf7d8a9    to
    fd0c868      
    Compare
  
    | @MaskRay Would be glad to see your feedback on the changes | 
        
          
                lld/ELF/Relocations.cpp
              
                Outdated
          
        
      | Err(ctx) << "both AUTH and non-AUTH GOT entries for '" << sym.getName() | ||
| << "' requested, but only one type of GOT entry per symbol is " | ||
| "supported" | ||
| << getLocation(ctx, *sec, sym, offset); | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to rebase and use printLocation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 6313f5c, thanks
        
          
                lld/ELF/SyntheticSections.cpp
              
                Outdated
          
        
      | // If address diversity is set and the discriminator | ||
| // is 0 then modifier = Place | ||
| uint8_t *dest = buf + authEntry.offset; | ||
| uint64_t key = authEntry.isSymbolFunc ? /*IA*/ 0b00 : /*DA*/ 0b10; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/*IA=*/ (preferred by both clang-format and clang-tidy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in b277e3b, thanks
|  | ||
| # RUN: llvm-mc -filetype=obj -triple=aarch64 err.s -o err.o | ||
|  | ||
| # RUN: not ld.lld err.o a.so -pie -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add --implicit-check-not=error: to ensure that there is no other error:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in b277e3b, thanks
| # RUN: ld.lld -shared a.o -o a.so | ||
|  | ||
| #--- ok.s | ||
|  | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unneeded blank line. we prefer not to add a blank line after #---
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in b277e3b, thanks
fd0c868    to
    b277e3b      
    Compare
  
            
          
                lld/ELF/Relocations.cpp
              
                Outdated
          
        
      | bool needsGotAuth = | ||
| (expr == RE_AARCH64_AUTH_GOT || expr == RE_AARCH64_AUTH_GOT_PAGE_PC); | ||
| uint16_t flags = sym.flags.load(std::memory_order_relaxed); | ||
| if (!(flags & NEEDS_GOT)) { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a data race due to load+store being separate atomic operations.
The loaded flags can be stale (another thread has modified flags) when setFlags is called.
In addition, we should avoid diagnostics in this function that is concurrently called. The existing code doesn't have diagnostics.
if (expr needs AUTH) {
  sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
} else {
  sym.setFlags(NEEDS_GOT | NEEDS_GOT_NONAUTH);
}
then check the NEEDS_GOT_NONAUTH & NEEDS_GOT_AUTH incompatibility in postScanRelocations. Yes, we will not be able to report locations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
        
          
                lld/ELF/SyntheticSections.cpp
              
                Outdated
          
        
      | void GotSection::addEntry(const Symbol &sym) { | ||
| assert(sym.auxIdx == ctx.symAux.size() - 1); | ||
| ctx.symAux.back().gotIdx = numEntries++; | ||
| if (sym.hasFlag(NEEDS_GOT_AUTH)) | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be moved to addGotAuthEntry
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 77361c7
d7336f6    to
    6f44978      
    Compare
  
    | @MaskRay Would be glad to see your feedback on the changes - previous comments should be addressed with latest fixes | 
6f44978    to
    8dba1cd      
    Compare
  
    | add x1, x1, :got_auth_lo12:zed | ||
|  | ||
| #--- err.s | ||
| # RUN: llvm-mc -filetype=obj -triple=aarch64 err.s -o err.o | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with the ... split-file %s %t && cd %t  pattern, you can omit -o /dev/null for not ld.lld commands.
without cd %t, -o /dev/null is needed so that we don't create a temporary file under CWD. Google's internal lit tester relies on this property, and it's generally a good idea to ensure that the tests run regardless of CWD.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # RUN: llvm-mc -filetype=obj -triple=aarch64 ok.s -o ok.o | ||
|  | ||
| # RUN: ld.lld ok.o a.so -pie -o ok1 | ||
| # RUN: llvm-readelf -r -S -x .got ok1 | FileCheck %s --check-prefix=EXTERNAL | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd avoid EXTERNAL and LOCAL as check prefixes as well since it's unclear what external/local mean in the test context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Support `R_AARCH64_AUTH_ADR_GOT_PAGE`, `R_AARCH64_AUTH_GOT_LO12_NC` and `R_AARCH64_AUTH_GOT_ADD_LO12_NC` GOT-generating relocations. For preemptible symbols, dynamic relocation `R_AARCH64_AUTH_GLOB_DAT` is emitted. Otherwise, we unconditionally emit `R_AARCH64_AUTH_RELATIVE` dynamic relocation since pointers in signed GOT needs to be signed during dynamic link time.
8dba1cd    to
    03f9115      
    Compare
  
    There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me, thanks!

Depends on #113811
Support
R_AARCH64_AUTH_ADR_GOT_PAGE,R_AARCH64_AUTH_GOT_LO12_NCandR_AARCH64_AUTH_GOT_ADD_LO12_NCGOT-generating relocations. For preemptiblesymbols, dynamic relocation
R_AARCH64_AUTH_GLOB_DATis emitted. Otherwise,we unconditionally emit
R_AARCH64_AUTH_RELATIVEdynamic relocation sincepointers in signed GOT needs to be signed during dynamic link time.